/******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd                  *
 ******************************************************************************
 *  $File Name$       : Usart.c                                               *
 *  $Author$          : ChipON AE/FAE Group                                   *
 *  $Data$            : 2021-07-8                                             *
 *  $Hard Version     : KF32A156-MINI-EVB_V1.2                                *
 *  $Description$     : This file provide flash information area and user 	  *
 * 						area operation function								  *
 *                      + Read any number of bytes                            *
 *                      + Erasure and writing of pages             			  *
 *                      + Data modification of any address          		  *
 *                      + Reading and writing of information area             *
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd                 *
 *  All rights reserved.                                                      *
 *                                                                            *
 *  This software is copyright protected and proprietary to                    *
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.                                 *
 ******************************************************************************
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *                     		REVISON HISTORY                               	  *
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  Data       Version  Author        Description                             *
 *  ~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  2021-07-08 00.02.00 FAE Group     Version 2.0 update                      *
 *                                                                            *
 *                                                                            *
 *****************************************************************************/

/******************************************************************************
**                      		Include Files                                 **
******************************************************************************/
#include "system_init.h"
#include "ChipMessageApi.h"

/*******************************************************************************
**                     		   Global Functions 		             	      **
*******************************************************************************/
/**
 *  @brief :Flash continue reads n bytes
 *  @param in :
 *              Address :Starting  address
 * 				Length :Read length
 *  @param out :Buffers :Read data to Buffers
 *  @retval :None
 */
void FlashReadNByte(unsigned int Address, unsigned int Length, unsigned char *Buffers)
{
	for (int i = 0; i < Length; i++)
	{
		Buffers[i] = *(unsigned char *)Address++;
	}
}

/**
 *  @brief :Erase N pages. The minimum erasure unit is 1K.
 * 			During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address :address aligned by 1K
 * 				Length :length like 1024 2048 3072 4096...
 *  @param out :None
 *  @retval :	CMD_SUCCESS									0x00
 *				BUSY 										0x0B
 *				SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 	0x09
 *				INVALID_SECTOR 								0x07
 */
uint32_t FlashEraseNPage(unsigned int Address, unsigned int Length)
{
	uint32_t FlashRetVal, IntState;
	IntState = (INT_CTL0 & INT_CTL0_AIE);
	SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	FlashRetVal = __FLASH_Erase__(Function_Parameter_Validate, Address, Length);
	if (IntState != 0)
		SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	return FlashRetVal;
}

/**
 *  @brief :Write N Kbytes. 
 * 			Erase first and write then.
 * 			During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address :address aligned by 1K
 * 				Length :length like 1024 2048 3072 4096...
 * 				Buffers:input data
 *  @param out :None
 *  @retval :	CMD_SUCCESS									0x00
 * 				SRC_ADDR_ERROR								0x02
 * 				DST_ADDR_ERROR								0x03
 * 				SRC_ADDR_NOT_MAPPED 						0x04
 *				DST_ADDR_NOT_MAPPED 						0x05
 *				COUNT_ERROR(not bytes 1K 2K 3K 4K)			0x06
 * 				INVALID_SECTOR 								0x07
 *				SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 	0x09
 *				BUSY 										0x0B
 */
uint32_t FlashWriteNKBytes(unsigned int Address, unsigned int Length, unsigned char *Buffers)
{
	uint32_t i,FlashRetVal, IntState;
	IntState = (INT_CTL0 & INT_CTL0_AIE);
	SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	FlashRetVal = __FLASH_Erase__(Function_Parameter_Validate, Address, Length);
	if (FlashRetVal == CMD_SUCCESS)
	{
		FlashRetVal = __FLASH_Program__(Function_Parameter_Validate, Address, Length, Buffers);
	}
	if (IntState != 0)
		SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	return FlashRetVal;
}

/**
 *  @brief :Write N bytes. 
 * 			Erase first and write then.
 * 			During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address :address aligned by 1K
 * 				Length :The length must be no more than 1K
 * 				Buffers:input data
 *  @param out :None
 *  @retval :	CMD_SUCCESS									0x00
 * 				SRC_ADDR_ERROR								0x02
 * 				DST_ADDR_ERROR								0x03
 * 				SRC_ADDR_NOT_MAPPED 						0x04
 *				DST_ADDR_NOT_MAPPED 						0x05
 *				COUNT_ERROR(not bytes 1K 2K 3K 4K)			0x06
 * 				INVALID_SECTOR 								0x07
 *				SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 	0x09
 *				BUSY 										0x0B
 */
uint32_t FlashEEWriteNBytes(unsigned int Address, unsigned int Length, unsigned char *Buffers)
{
	uint8_t ReadTempBuffer[1024];
	uint32_t FlashRetVal = CMD_SUCCESS, IntState;
	uint32_t i,PageNum, AddrNum, Writelen;

	if (Length > 0x400)
		FlashRetVal = INVALID_SECTOR;
	while((FlashRetVal == CMD_SUCCESS))
	{
		IntState = (INT_CTL0 & INT_CTL0_AIE);
		SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
		PageNum = Address / 0x400;
		AddrNum = Address % 0x400;
		FlashReadNByte((PageNum << 10),  0x400, ReadTempBuffer);
		__FLASH_Erase__(Function_Parameter_Validate, (PageNum << 10), 0x400);
		if ((AddrNum + Length) <= 0x400)
		{
			Writelen = Length;
		}
		else
		{
			Writelen = 0x400 - AddrNum;
		}
		for (i = 0; i < Writelen; i++)
		{
			ReadTempBuffer[AddrNum + i] = *Buffers++;
		}
		__FLASH_Program__(Function_Parameter_Validate, (PageNum << 10), 0x400, ReadTempBuffer);
		if ((AddrNum + Length) > 0x400)
		{
			FlashReadNByte((PageNum + 1) << 10, 0x400, ReadTempBuffer);
			__FLASH_Erase__(Function_Parameter_Validate, ((PageNum + 1) << 10), 0x400);
			Writelen = (AddrNum + Length) - 0x400;
			for (i = 0; i < Writelen; i++)
			{
				ReadTempBuffer[i] = *Buffers++;
			}
			__FLASH_Program__(Function_Parameter_Validate, (PageNum + 1) << 10, 0x400, ReadTempBuffer);
		}
		if (IntState != 0)
			SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
		FlashRetVal = CMD_SUCCESS;
		break;
	}
	return FlashRetVal;
}

/**
 *  @brief :Compare data in Flash and RAM
 *  		During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address:address aligned by 1K
 * 				Length :must is 1024
 * 				Buffers:input data
 *  @param out :None
 *  @retval :	CMD_SUCCESS									0x00
 *				COUNT_ERROR(not bytes 1K 2K 3K 4K)			0x06
 * 				COMPARE_ERROR								0x0A
 *				ADDR_ERROR									0x0D
 *				ADDR_NOT_MAPPED								0x0E
 */
uint32_t FlashCheckNBytes(unsigned int Address, unsigned int Length, unsigned char *Buffers)
{
	uint32_t FlashRetVal, IntState;
	IntState = (INT_CTL0 & INT_CTL0_AIE);
	SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	FlashRetVal = __FLASH_Check__(Address, Length, Buffers);
	if (IntState != 0)
		SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	return FlashRetVal;
}

/**
 *  @brief :Write 1K bytes to the user information area
 * 			Erase first defult
 * 			During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address :must is 0x1C00
 * 				Length :must is 1024
 * 				Buffers:must is 1024 bytes data
 *  @param out :None
 *  @retval :	CMD_SUCCESS 									0x00
 *				SRC_ADDR_ERROR									0x02
 *				DST_ADDR_ERROR									0x03
 *				SRC_ADDR_NOT_MAPPED 							0x04
 *				DST_ADDR_NOT_MAPPED 							0x05
 *				COUNT_ERROR(not bytes 1K 2K 3K 4K)				0x06
 *				SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 		0x09
 *				BUSY 											0x0B
 */

uint32_t FlashCFGUserWrite(unsigned int Address,unsigned int Length,unsigned int *Buffers)
{
	uint32_t FlashRetVal, IntState;
	IntState = (INT_CTL0 & INT_CTL0_AIE);
	SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	FlashRetVal = __FLASHCFGUSER_Program__(Function_Parameter_Validate, Address, Length, Buffers);
	if (IntState != 0)
		SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	return FlashRetVal;
}

/**
 *  @brief :Read 1K bytes to the user information area
 * 			The minimum eadout is 64bit
 * 			During this period, the whole play will be close !!!
 * 			Recovery interrupt at the end !!!
 *  @param in :
 *              Address :must between 0x1C00-0x1FFF ,with length ,all data must be between 0x1C00-0x1FFF
 * 				Length :must align by 2,like  4 8 12 16 ....
 *  @param out :Buffers:must big then length,like sizeof(buffers)==length+1, stores begin buffers[1] of readout
 *  @retval :	CMD_SUCCESS 									0x00
 *				SRC_ADDR_ERROR									0x02
 *				DST_ADDR_ERROR									0x03
 *				SRC_ADDR_NOT_MAPPED 							0x04
 *				DST_ADDR_NOT_MAPPED 							0x05
 *				COUNT_ERROR(not bytes 1K 2K 3K 4K)				0x06
 *				SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 		0x09
 *				BUSY 											0x0B
 */

uint32_t FlashCFGUserRead(unsigned int Address,unsigned int Length,unsigned int *Buffers)
{
	uint32_t FlashRetVal, IntState;
	IntState = (INT_CTL0 & INT_CTL0_AIE);
	SFR_CLR_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	FlashRetVal = __FLASHCFGUSER_Read__(Address, Length, Buffers);
	if (IntState != 0)
		SFR_SET_BIT_ASM(INT_CTL0, INT_CTL0_AIE_POS);
	return FlashRetVal;
}
